Table locations;
int rowCount, curPoint;
PImage mapImage;
PVector ellipsePos;
static float epsilon = 0.0001;
PVector startPt, endPt, speed;
boolean []visited;

void setup()
{
  // load data and map
  mapImage = loadImage("../res/map.png");
  locations = new Table("../res/locations.tsv");
  rowCount = locations.getRowCount();
  visited = new boolean[rowCount];
  visited[0] = true;
  
  // prepare
  curPoint = 1;
  startPt = new PVector(locations.getFloat(curPoint - 1, 1), 
                        locations.getFloat(curPoint - 1, 2));
  endPt = new PVector(locations.getFloat(curPoint, 1), 
                      locations.getFloat(curPoint, 2));
  getSpeed(startPt, endPt);
  ellipsePos = new PVector(startPt.x, startPt.y);
  
  // setup
  size(mapImage.width, mapImage.height);
  smooth();
  noStroke();
}

void getSpeed(PVector startPos, PVector endPos)
{
  speed = new PVector(endPos.x - startPos.x, endPos.y - startPos.y);
  speed.normalize();
}

void draw()
{
  println("startPos.x " + startPt.x + " startPos.y" + startPt.y);
  println("endPos.x " + endPt.x + " endPos.y " + endPt.y);
  println("ellipse.x " + ellipsePos.x + " ellipse.y " + ellipsePos.y);
  image(mapImage, 0, 0);
  
  for (int row=0; row<rowCount; ++row) {
    float x = locations.getFloat(row, 1);
    float y = locations.getFloat(row, 2);
    if (visited[row]) fill(192, 0, 0);
    else fill(230, 123, 90);
    ellipse(x, y, 9, 9);
  }
  
  fill(125);
  if (isOnline(ellipsePos, startPt, endPt)) {
    ellipse(ellipsePos.x, ellipsePos.y, 5, 5);
    ellipsePos.add(speed);
  } else {
    visited[curPoint] = true;
    ++curPoint;
    if (curPoint == rowCount) {
      curPoint = 1;
      resetMap();
    }
    ellipsePos.x = locations.getFloat(curPoint-1, 1);
    ellipsePos.y = locations.getFloat(curPoint-1, 2);
    startPt.x = ellipsePos.x;
    startPt.y = ellipsePos.y;
    endPt.x = locations.getFloat(curPoint, 1);
    endPt.y = locations.getFloat(curPoint, 2);
    getSpeed(startPt, endPt);
  }
}

void resetMap()
{
  for (int i=0; i<rowCount; ++i) {
    visited[i] = false;
  }
}

boolean isOnline(PVector pt, PVector startPos, PVector endPos)
{
  float dis1 = startPos.dist(pt);
  float dis2 = pt.dist(endPos);
  float disa = startPos.dist(endPos);
  println("dis1 " + dis1 + " dis2 " + dis2 + " disa " + disa);
  if (abs(dis1 + dis2 - disa) < epsilon) return true;
  else return false;
}

class Table {
  String[][] data;
  int rowCount;
  
  Table() 
  {
    data = new String[10][10];
  }
  
  Table(String filename)
  {
    String[] rows = loadStrings(filename);
    data = new String[rows.length][];
    
    for (int i=0; i<rows.length; ++i) {
      if (trim(rows[i]).length() == 0
          || rows[i].startsWith("#")) {
            continue; // Skip blank lines and comment lines
      }
      data[rowCount++] = split(rows[i], TAB);
    }
    data = (String[][])subset(data, 0, rowCount);
  }
  
  int getRowCount()
  {
    return rowCount;
  }
  
  float getFloat(int rowIndex, int column) 
  {
    return parseFloat(getString(rowIndex, column));
  }
  
  String getString(int rowIndex, int column)
  {
    return data[rowIndex][column];
  }
 
}
